package svg.sample;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;

import javax.swing.*;

import com.neural.*;

public class Quiz extends JDialog implements Runnable {

    /**
     * The neural network.
     */
    KohonenNetwork net;

    /**
     * The background thread used for training.
     */
    Thread trainThread = null;

    private Entry entry;

    private QuizCanvas canvas;
    private JButton btnClear;
    private JButton btnRecognize;
    private JButton btnClose;

    DefaultListModel letterListModel = new DefaultListModel();

    public Quiz(JFrame owner, String title) {
        super(owner, title, true);

        entry = new Entry();

        canvas = new QuizCanvas();

        //size of the dialog
        setSize(400, 300);

        // add the components to the container
        Container contentPane = getContentPane();
        contentPane.add(canvas, BorderLayout.CENTER);
        contentPane.add(createSouthPanel(), BorderLayout.SOUTH);
    }

    private JPanel createSouthPanel() {
        JPanel panel = new JPanel(new FlowLayout());

        btnRecognize = new JButton("Recognize");
        btnRecognize.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                recognize();
            }
        });

        btnClear = new JButton("Clear");
        btnClear.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                clear();
            }
        });

        btnClose = new JButton("Close");
        btnClose.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                close();
            }
        });

        panel.add(btnRecognize);
        panel.add(btnClear);
        panel.add(btnClose);

        return panel;
    }

    private void close() {
        this.close();
    }


    private void clear() {
        canvas.clear();
    }

    private void recognize() {
        double input[] =
            new double[Entry.DOWNSAMPLE_WIDTH * Entry.DOWNSAMPLE_HEIGHT];
        int idx = 0;
        SampleData ds = canvas.getSampleData();
        for (int y = 0; y < ds.getHeight(); y++) {
            for (int x = 0; x < ds.getWidth(); x++) {
                input[idx++] = ds.getData(x, y) ? .5 : -.5;
            }
        }

        double normfac[] = new double[1];
        double synth[] = new double[1];

        int best = net.winner(input, normfac, synth);
        String map[] = mapNeurons();
        JOptionPane.showMessageDialog(this,
                                      "  " + map[best] + "   (Neuron #"
                                      + best + " fired)", "That Letter Is",
                                      JOptionPane.PLAIN_MESSAGE);
       //if don't want the neuron # fired use this message dialog
        /*JOptionPane.showMessageDialog(this,
                                      "  " + map[best], "That Letter Is",
                                      JOptionPane.PLAIN_MESSAGE);*/

    }

    public void train(String letter, BufferedImage img) {
        SampleData ds = entry.downSample(letter, img);
        letterListModel.add(0, ds);

        trainThread = new Thread(this);
        trainThread.start();
    }


    private String[] mapNeurons() {
        String map[] = new String[letterListModel.size()];
        double normfac[] = new double[1];
        double synth[] = new double[1];

        for (int i = 0; i < map.length; i++) {
            map[i] = "?";
        }

        for (int i = 0; i < letterListModel.size(); i++) {
            double input[] = new double[Entry.DOWNSAMPLE_WIDTH * Entry.DOWNSAMPLE_HEIGHT];
            int idx = 0;
            SampleData ds = (SampleData) letterListModel.getElementAt(i);
            for (int y = 0; y < ds.getHeight(); y++) {
                for (int x = 0; x < ds.getWidth(); x++) {
                    input[idx++] = ds.getData(x, y) ? .5 : -.5;
                }
            }

            int best = net.winner(input, normfac, synth);
            map[best] = ds.getLetter();
        }
        return map;
    }


    /**
     * Run method for the background training thread.
     */
    public void run() {
        try {
            int inputNeuron = Entry.DOWNSAMPLE_HEIGHT *
                Entry.DOWNSAMPLE_WIDTH;
            int outputNeuron = letterListModel.size();

            TrainingSet set = new TrainingSet(inputNeuron, outputNeuron);
            set.setTrainingSetCount(letterListModel.size());

            for (int t = 0; t < letterListModel.size(); t++) {
                int idx = 0;
                SampleData ds = (SampleData) letterListModel.getElementAt(t);
                for (int y = 0; y < ds.getHeight(); y++) {
                    for (int x = 0; x < ds.getWidth(); x++) {
                        set.setInput(t, idx++, ds.getData(x, y) ? .5 : -.5);
                    }
                }
            }

            net = new KohonenNetwork(inputNeuron, outputNeuron);
            net.setTrainingSet(set);
            net.learn();
        }
        catch (Exception e) {
            JOptionPane.showMessageDialog(this, "Error: " + e,
                                          "Training",
                                          JOptionPane.ERROR_MESSAGE);
        }
    }

}
